import  numpy  as np
import math as m
import time
class Taxonomy:
    def __init__(self,Matrix,weight=[],q=3):
        '''
        :param Matrix: 决策化矩阵
        :param q: q值
        '''
        self.Matrix=Matrix
        self.q=q
    # 加法
    def addition(self,Ivq1,Ivq2,q):
        '''
        加法
        :param Ivq1:区间值
        :param Ivq2:区间值
        :param q:q值
        :return:
        '''
        a,b,c,d=Ivq1[0][0],Ivq1[0][1],Ivq1[1][0],Ivq1[1][1]
        e,f,g,h=Ivq2[0][0],Ivq2[0][1],Ivq2[1][0],Ivq2[1][1]
        u1=a**q+e**q-(a**q)*(e**q)
        u2=b**q+f**q-(b**q)*(f**q)
        v1=c*g
        v2=h*d
        return ([u1,u2],[v1,v2])

    # 减法
    def subtraction(self,Ivq1,Ivq2,q):
        '''
        减法
        :param Ivq1:区间值
        :param Ivq2:区间值
        :param q:q值
        :return:
        '''
        a,b,c,d=Ivq1[0][0],Ivq1[0][1],Ivq1[1][0],Ivq1[1][1]
        e,f,g,h=Ivq2[0][0],Ivq2[0][1],Ivq2[1][0],Ivq2[1][1]
        u1=a*g
        u2=b*h
        v1=(c**q+e**q-(c**q)*(e**q))**(1/q)
        v2=(d**q+f**q-(d**q)*(f**q))**(1/q)
        return ([u1, u2],[v1, v2])

    # 乘法
    def multiplication(self,Ivq1,Ivq2,q):
        '''
        乘法
        :param Ivq1:区间值
        :param Ivq2:区间值
        :param q:q值
        :return:
        '''
        a, b, c, d = Ivq1[0][0], Ivq1[0][1], Ivq1[1][0], Ivq1[1][1]
        e, f, g, h = Ivq2[0][0], Ivq2[0][1], Ivq2[1][0], Ivq2[1][1]
        u1 = a * e
        u2 = b * f
        v1 = (c ** q + g ** q - (c ** q) * (g ** q)) ** (1 / q)
        v2 = (d ** q + h ** q - (d ** q) * (h ** q)) ** (1 / q)
        return ([u1, u2], [v1, v2])

    # 除法
    def division(self,Ivq1,Ivq2,q):
        '''
        除法
        :param Ivq1:区间值
        :param Ivq2:区间值
        :param q:q值
        :return:
        '''
        a, b, c, d = Ivq1[0][0], Ivq1[0][1], Ivq1[1][0], Ivq1[1][1]
        e, f, g, h = Ivq2[0][0], Ivq2[0][1], Ivq2[1][0], Ivq2[1][1]
        u1 = (a ** q + g ** q - (a ** q) * (g ** q)) ** (1 / q)
        u2 = (b ** q + h ** q - (b ** q) * (h ** q)) ** (1 / q)
        v1 = c*e
        v2 = d*f
        return ([u1, u2], [v1, v2])

    # 次方运算
    def Exponentiation(self,Ivq1,q,n):
        '''
        次方运算
        :param Ivq1:
        :param q:
        :param n:开多少次方
        :return:
        '''
        a, b, c, d = Ivq1[0][0], Ivq1[0][1], Ivq1[1][0], Ivq1[1][1]
        u1 = a ** n
        u2 = b ** n
        v1 =(1-((1-(c**q))**n))**(1/q)
        v2 =(1-((1-(d**q))**n))**(1/q)
        return ([u1, u2], [v1, v2])

    # 数乘运算
    def Numbermulti(self,Ivq,n,q):
        '''
        数乘
        :param Ivq: 区间值
        :param n: 实数
        :param q:
        :return:
        '''
        a, b, c, d = Ivq[0][0], Ivq[0][1], Ivq[1][0], Ivq[1][1]
        u1 = (1-((1-a ** q)**n)) ** (1/q)
        u2 = (1-((1-b ** q)**n)) ** (1/q)
        v1 = c **n
        v2 = d **n
        return ([u1, u2], [v1, v2])

    #求正负理想解
    def getPosNegPoint(self, NormalizedMatrix):
        '''
        求正负理想解
        :param NormalizedMatrix: 区间值矩阵
        :param q: q值
        :return: 传入区间值矩阵的贴近度矩阵
        '''
        Row, Column = len(NormalizedMatrix), len(NormalizedMatrix[0])
        for i in range(Row):
            Positiveline, Negativeline = [], []
            for j in range(Column):
                ##求理想点
                Positiveidu1 = np.max((((NormalizedMatrix[:, j])[:, 0])[:, 0]))
                Positiveidu2 = np.max((((NormalizedMatrix[:, j])[:, 0])[:, 1]))
                Positiveidv1 = np.min((((NormalizedMatrix[:, j])[:, 1])[:, 0]))
                Positiveidv2 = np.min((((NormalizedMatrix[:, j])[:, 1])[:, 1]))
                Negativeidu1 = np.min((((NormalizedMatrix[:, j])[:, 0])[:, 0]))
                Negativeidu2 = np.min((((NormalizedMatrix[:, j])[:, 0])[:, 1]))
                Negativeidv1 = np.max((((NormalizedMatrix[:, j])[:, 1])[:, 0]))
                Negativeidv2 = np.max((((NormalizedMatrix[:, j])[:, 1])[:, 1]))
                Positiveline.append(([Positiveidu1, Positiveidu2], [Positiveidv1, Positiveidv2]))
                Negativeline.append(([Negativeidu1, Negativeidu2], [Negativeidv1, Negativeidv2]))

        return Positiveline, Negativeline
    #转换成实数
    def getscore(self,IVq):
        '''
        我们提出的得分函数
        :param IVq:区间值
        :param q:q值
        :return:
        '''
        a = IVq[0][0]
        b = IVq[0][1]
        c = IVq[1][0]
        d = IVq[1][1]
        return (m.log(a + b + c + d + 1) + (b - a) + (d - c) ** 2 + (a - c + b - d) * m.log(3) / 2) / (2 * m.log(3))



    #求属性的均值
    def get_r(self,Matrix,q):
        '''
        求属性的均值
        :param Matrix: 原始矩阵
        :return: 返回一个平均值
        '''
        row,col=len(Matrix),len(Matrix[0])
        r=[]
        for i in range(col):
            sum = Matrix[0][i]
            for j in range(1,row):
                sum=self.addition(sum,Matrix[j][i],q)
            r.append(self.Numbermulti(sum,1/row,q))
        return r

    #求属性的标准差
    def get_S(self,Matrix,q,r):
        '''
        :param Matrix: 原始矩阵
        :param q: q值
        :param r: 均值
        :return: 标准差
        '''
        row,col=len(Matrix[0]),len(Matrix)
        S=[]
        for i in range(col):
            sum=self.Exponentiation(self.subtraction(Matrix[0][i],r[i],q),q,2)
            for j in range(1,row):
                n=self.Exponentiation(self.subtraction(Matrix[j][i],r[i],q),q,2)
                sum=self.addition(sum,n,q)
            S.append(self.Numbermulti(sum,1/col,q))
        return S

    #计算复合距离矩阵
    def complex_disMaxtir(self,Matrix,q):
        '''
        :param Matrix: 标准化之后的矩阵
        :param q: q值
        :return: 返回复合距离矩阵
        '''
        row,col=len(Matrix[0]),len(Matrix)
        for a in range(col):
            for b in range(a,row):
                sum=np.zeros((2,2))
                for j in range(row):
                    n=self.Exponentiation(self.subtraction(Matrix[a][j],Matrix[b][j],q),q,2)
                    sum=self.addition(sum,n,q)
                Matrix[a][b]=self.Exponentiation(sum,q,1/2)
        for i in range(col):
            for j in range(row):
                Matrix[i][j]=Matrix[j][i]
        return  Matrix

    #均质化
    def getO_So(self,Matrix,q):
        '''
        :param Matrix: 复合距离矩阵
        :param q: q值
        :return: 均质化后的行均值和行标准差
        '''
        Pos,Neg=self.getPosNegPoint(Matrix)
        col=len(Matrix)
        sum=Neg[0]
        for i in range(1,col):
            sum=self.addition(sum,Neg[i],q)
        O_mean=self.Numbermulti(sum,1/col,q)
        for i in range(col):
            sum=self.Exponentiation(self.subtraction(Neg[i],O_mean,q),q,2)
        So=self.Exponentiation(self.Numbermulti(sum,q,1/col),q,1/2)
        return O_mean,So

    #判断是否是齐次的
    def condition(self,Matrix,q):
        '''
        判断这个矩阵是否是其次的
        :param Matrix:复合距离矩阵
        :param O_mean:最小距离平均值
        :param So:最小距离标准差
        :return:
        '''
        #求出领域
        Pos,Minline=self.getPosNegPoint(Matrix)
        O_mean,So=self.getO_So(Matrix,q)
        O_mean = self.getscore(O_mean)
        So = self.getscore(So)
        for i in range(len(Matrix)):
            Minline[i] = self.getscore(Minline[i])
        Minline=np.array(Minline)
        return  O_mean,So,Minline
    def Homoge(self,Matrix,q):
        '''
        根据condition函数判断是否是齐次的
        :param q:
        :return:
        '''
        mean,S,Minline=self.condition(Matrix,q)
        sum_up=mean+2*S
        sum_down=mean-2*S
        sum=[]
        for i in range(len(Matrix)):
            if Minline[i]>sum_up and Minline[i]<sum_down:
                sum.append(i)
        if len(sum):
            return sum
        else:
            return 1

    #如果不是齐次的:
    def notqi(self,Matrix,q):
        for i in range(len(Matrix)):
            if i in sum:
                Matrix=np.delete(Matrix,i,axis=0)
        # 第三步，复合距离矩阵
        complex_disMatrix = self.complex_disMaxtir(Matrix, q)
        # 第四步，判断矩阵是否是齐次的
        sum = self.Homoge(complex_disMatrix, q)
        return sum

    #发展方式
    def Develop_pattern(self,Matrix,q):
        '''
        确定发展模式
        :param Matrix: 标准化后的矩阵
        :param q: q值
        :return:
        '''
        Pos,Neg=self.getPosNegPoint(Matrix)
        row, col = len(Matrix[0]), len(Matrix)
        Cio=[]
        for  i  in range(col):
            sum=Matrix[0][i]
            for j in range(1,row):
                t=self.Exponentiation(self.subtraction(Matrix[j][i],Neg[j],q),q,2)
                sum=self.addition(sum,t,q)
            Cio.append(self.Exponentiation(sum,q,1/2))
        return  Cio

    #返回最终的排名
    def rank(self,Cio,Matrix):
        for i in range(len(Matrix)):
            Cio[i]=self.getscore(Cio[i])
        Cio_mean=np.mean(Cio)
        SCio=np.std(Cio)
        sum=Cio_mean+2*SCio
        final=[]
        for i in range(len(Cio)):
            final.append(Cio[i]/sum)
        return final
    #返回最后的结果
    def getResult(self,Matrix,q):
        '''
        :return: 最终的决策结果
        '''
        #第三步，复合距离矩阵
        complex_disMatrix=self.complex_disMaxtir(Matrix,q)
        #第四步，判断矩阵是否是齐次的
        sum1=self.Homoge(complex_disMatrix,q)
        #第五步，确认发展模式
        while sum1!=1:
            self.notqi()
        Cio=self.Develop_pattern(Matrix,q)
        final=self.rank(Cio,Matrix)
        # print(Cio)
        final=[i/sum(final) for i in final]
        return  final
if __name__ == "__main__":
    Matrix = np.array([[([0.58, 0.75], [0.1, 0.2]),  ([0.7, 0.78], [0.2, 0.3]),  ([0.5, 0.78], [0.1, 0.2]), ([0.65, 0.7], [0.3, 0.35]), ([0.4, 0.5], [0.5, 0.6])],
                       [([0.5, 0.6], [0.1, 0.2]),    ([0.75, 0.78], [0.2, 0.3]), ([0.6, 0.78], [0.1, 0.15]),([0.7, 0.8], [0.2, 0.3]),   ([0.5, 0.6], [0.4, 0.5])],
                       [([0.5, 0.78], [0.1, 0.2]),   ([0.6, 0.7], [0.3, 0.4]),   ([0.7, 0.78], [0.2, 0.3]), ([0.6, 0.7], [0.3, 0.4]),   ([0.35, 0.45], [0.5, 0.65])],
                       [([0.75, 0.78], [0.2, 0.3]), ([0.6, 0.75], [0.2, 0.3]),  ([0.7, 0.78], [0.2, 0.3]), ([0.55, 0.65], [0.3, 0.4]), ([0.35, 0.4], [0.6, 0.65])],
                       [([0.6, 0.75], [0.3, 0.4]),   ([0.5, 0.6], [0.4, 0.5]),   ([0.6, 0.7], [0.3, 0.4]),  ([0.5, 0.6], [0.4, 0.5]),   ([0.1, 0.2], [0.4, 0.5])]])
    start = time.perf_counter()
    taxonomy= Taxonomy(Matrix, [],3)
    result = taxonomy.getResult(Matrix,3)
    print(result)
    # complex_disMatrix=taxonomy.complex_disMaxtir(Matrix,3)
    # sum = taxonomy.Homoge(complex_disMatrix, 3)
    # O_mean, So, Minline=taxonomy.condition(Matrix,3)
    # print(O_mean+2*So)
    # print(O_mean - 2 * So)
    # print(Minline)
    # print(f'U={np.round(result,4)}')
    # end = time.perf_counter()
    # print('finish all in %s' % str(end - start))
